home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xmbase-grok-1.2 / cardwin.c < prev    next >
C/C++ Source or Header  |  1995-06-25  |  25KB  |  776 lines

  1. /*
  2.  * draw card canvas. This canvas is used by the form editor to allow the
  3.  * user to position items in a form and to set their size. The canvas is
  4.  * drawn using Xlib calls; items are represented by colored rectangles.
  5.  *
  6.  *    destroy_card_menu(card)
  7.  *    create_card_menu(form, dbase, wform)
  8.  *    card_readback_texts(card, nitem)
  9.  *    format_time_data(data, timefmt)
  10.  *    fillout_card(card, deps)
  11.  */
  12.  
  13. #include "config.h"
  14. #include <X11/Xos.h>
  15. #include <stdlib.h>
  16. #include <assert.h>
  17. #include <Xm/Xm.h>
  18. #include <Xm/MainW.h>
  19. #include <Xm/Form.h>
  20. #include <Xm/Frame.h>
  21. #include <Xm/LabelP.h>
  22. #include <Xm/PushBP.h>
  23. #include <Xm/PushBG.h>
  24. #include <Xm/ToggleB.h>
  25. #include <Xm/DrawingA.h>
  26. #include <Xm/ScrolledW.h>
  27. #include <Xm/Text.h>
  28. #include <Xm/Protocols.h>
  29. #include <X11/StringDefs.h>
  30. #include <time.h>
  31. #include "grok.h"
  32. #include "form.h"
  33. #include "proto.h"
  34.  
  35. static void create_item_widgets(CARD *, int);
  36. static void mwm_quit_callback
  37.             (Widget, XtPointer, XmToggleButtonCallbackStruct *);
  38. static void chart_expose_callback
  39.             (Widget, XtPointer, XmDrawingAreaCallbackStruct *);
  40. static void card_callback(Widget, XtPointer, XmToggleButtonCallbackStruct *);
  41. void card_readback_texts(CARD *, int);
  42. static BOOL store(CARD *, int, char *);
  43.  
  44.  
  45. extern Display        *display;    /* everybody uses the same server */
  46. extern GC        gc;        /* everybody uses this context */
  47. extern XtAppContext    app;        /* application handle, for actions */
  48. extern struct pref    pref;        /* global preferences */
  49. extern CARD         *curr_card;    /* card being displayed in main win */
  50. extern Pixel        color[NCOLS];    /* colors: COL_* */
  51. extern XFontStruct    *font[NFONTS];    /* fonts: FONT_* */
  52. extern Widget        mainwindow;    /* popup menus hang off main window */
  53. extern char        *switch_name;    /* if switch stmt was found, name to */
  54. extern char        *switch_expr;    /* .. switch to and search expression*/
  55.  
  56.  
  57. /*
  58.  * Read back any unread text widgets. Next, destroy the card widgets, and
  59.  * the window if there is one (there is one if create_card_menu() was called
  60.  * with wform==0). All the associated data structures are cleared, except
  61.  * the referenced database, if any. Do not use the CARD struct after calling
  62.  * destroy_card_menu().
  63.  */
  64.  
  65. void destroy_card_menu(
  66.     register CARD    *card)        /* card to destroy */
  67. {
  68.     int        i;        /* item counter */
  69.  
  70.     if (!card)
  71.         return;
  72.     card_readback_texts((CARD *)card, -1);
  73.     XtUnmanageChild(XtParent(card->wform));
  74.     XtDestroyWidget(card->wform);
  75.     if (card->shell)
  76.         XtPopdown(card->shell);
  77.     for (i=0; i < card->nitems; i++) {
  78.         card->items[i].w0 = 0;
  79.         card->items[i].w1 = 0;
  80.     }
  81.     card->shell = card->wform = 0;
  82. }
  83.  
  84.  
  85. /*
  86.  * create a card, based on the form struct (which describes structure and
  87.  * layout) and a database struct (which describes the contents). The database
  88.  * is not accessed, it is stored to permit later entry through the form's
  89.  * callbacks into the database. In addition, a form widget to install into
  90.  * must be given. If a null form widget is passed, this routine creates a
  91.  * new window with a form widget in it. The new card is not filled out.
  92.  * A card data structure is returned that allows printing into the card,
  93.  * entering data into the database through the card, and destroying the card.
  94.  */
  95.  
  96. CARD *create_card_menu(
  97.     FORM        *form,        /* form that controls layout */
  98.     DBASE        *dbase,        /* database for callbacks, or 0 */
  99.     Widget        wform)        /* form widget to install into, or 0 */
  100. {
  101.     CARD        *card;        /* new card being allocated */
  102.     int        xs, ys, ydiv;    /* card size and divider */
  103.     Arg        args[15];
  104.     int        n;
  105.     Atom        closewindow;
  106.  
  107.                             /*-- alloc card --*/
  108.     n = sizeof(CARD) + sizeof(struct carditem) * form->nitems;
  109.     if (!(card = (CARD *)malloc(n)))
  110.         return((CARD *)0);
  111.     mybzero((void *)card, n);
  112.     card->form   = form;
  113.     card->dbase  = dbase;
  114.     card->row    = -1;
  115.     card->nitems = form->nitems;
  116.     if (!mainwindow)
  117.         return((CARD *)card);
  118.     xs   = pref.scale * form->xs;
  119.     ys   = pref.scale * form->ys;
  120.     ydiv = pref.scale * form->ydiv;
  121.                             /*-- make form --*/
  122.     if (wform) {
  123.         XtUnmanageChild(wform);
  124.         n = 0;
  125.         XtSetArg(args[n], XmNtopAttachment,    XmATTACH_FORM);    n++;
  126.         XtSetArg(args[n], XmNbottomAttachment,    XmATTACH_FORM);    n++;
  127.         XtSetArg(args[n], XmNleftAttachment,    XmATTACH_FORM);    n++;
  128.         XtSetArg(args[n], XmNrightAttachment,    XmATTACH_FORM);    n++;
  129.         XtSetArg(args[n], XmNwidth,        xs+6);        n++;
  130.         XtSetArg(args[n], XmNheight,        ys+6);        n++;
  131.         XtSetArg(args[n], XmNscrollingPolicy,    XmAUTOMATIC);    n++;
  132.         XtSetArg(args[n], XmNresizable,        False);        n++;
  133.         card->wform = XtCreateManagedWidget("wform",
  134.                 xmFormWidgetClass, wform, args, 0);
  135.         XtManageChild(wform);
  136.     } else {
  137.         n = 0;
  138.         XtSetArg(args[n], XmNdeleteResponse,    XmDO_NOTHING);    n++;
  139.         XtSetArg(args[n], XmNiconic,        False);        n++;
  140.         card->shell = XtAppCreateShell("Card", "Grok",
  141.                 applicationShellWidgetClass, display, args, n);
  142.         set_icon(card->shell, 1);
  143.         n = 0;
  144.         XtSetArg(args[n], XmNwidth,        xs+6);        n++;
  145.         XtSetArg(args[n], XmNheight,        ys+6);        n++;
  146.         XtSetArg(args[n], XmNresizable,        False);        n++;
  147.         card->wform = XtCreateManagedWidget("wform",
  148.                 xmFormWidgetClass, card->shell, args, n);
  149.         XtPopup(card->shell, XtGrabNone);
  150.         closewindow = XmInternAtom(display, "WM_DELETE_WINDOW", False);
  151.         XmAddWMProtocolCallback(card->shell, closewindow,
  152.                 (XtCallbackProc)mwm_quit_callback, NULL);
  153.     }
  154.     XtManageChild(card->wform);
  155.     card->wstat = card->wcard = 0;
  156.     n = 0;
  157.     XtSetArg(args[n], XmNtopAttachment,      XmATTACH_FORM);    n++;
  158.     if (ydiv) {
  159.         if (ydiv >= ys) {
  160.          XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM);    n++;
  161.         }
  162.         XtSetArg(args[n], XmNleftAttachment,  XmATTACH_FORM);    n++;
  163.         XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM);    n++;
  164.         XtSetArg(args[n], XmNwidth,          xs+6);        n++;
  165.         XtSetArg(args[n], XmNheight,      ydiv);        n++;
  166.         XtSetArg(args[n], XmNresizable,      FALSE);        n++;
  167.         card->wstat = XtCreateManagedWidget("staticform",
  168.             xmFormWidgetClass, card->wform, args, n);
  169.         n = 0;
  170.         XtSetArg(args[n], XmNtopAttachment,      XmATTACH_WIDGET);    n++;
  171.         XtSetArg(args[n], XmNtopWidget,      card->wstat);        n++;
  172.         XtSetArg(args[n], XmNtopOffset,      8);            n++;
  173.     }
  174.     if (ydiv < ys) {
  175.         XtSetArg(args[n], XmNleftAttachment,  XmATTACH_FORM);    n++;
  176.         XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM);    n++;
  177.         XtSetArg(args[n], XmNbottomAttachment,XmATTACH_FORM);    n++;
  178.         XtSetArg(args[n], XmNwidth,          xs+6);        n++;
  179.         XtSetArg(args[n], XmNheight,      ys-ydiv+6);        n++;
  180.         XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC);        n++;
  181.         XtSetArg(args[n], XmNshadowType,      XmSHADOW_IN);        n++;
  182.         XtSetArg(args[n], XmNresizable,      FALSE);        n++;
  183.         card->wcard = XtCreateManagedWidget("cardframe",
  184.                xmFrameWidgetClass, card->wform, args, n);
  185.         card->wcard = XtCreateManagedWidget("cardform",
  186.             xmFormWidgetClass, card->wcard, NULL, 0);
  187.         n = 0;
  188.         XtSetArg(args[n], XmNwidth,          xs);            n++;
  189.         XtSetArg(args[n], XmNheight,      ys-ydiv);        n++;
  190.         XtSetArg(args[n], XmNhighlightThickness,0);            n++;
  191.         (void)XtCreateManagedWidget("",
  192.             xmLabelWidgetClass, card->wcard, args, n);
  193.     }
  194.                             /*-- create items --*/
  195.     for (n=0; n < card->nitems; n++)
  196.         create_item_widgets(card, n);
  197.     return(card);
  198. }
  199.  
  200.  
  201. /*
  202.  * create the widgets in the card menu, at the location specified by the
  203.  * item in the form. The resulting widgets are stored in the card item.
  204.  */
  205.  
  206. #define JUST(j) (j==J_LEFT   ? XmALIGNMENT_BEGINNING :    \
  207.          j==J_RIGHT  ? XmALIGNMENT_END        \
  208.                  : XmALIGNMENT_CENTER)
  209.  
  210. static void create_item_widgets(
  211.     CARD        *card,        /* card the item is added to */
  212.     int        nitem)        /* number of item being added */
  213. {
  214.     ITEM        item;        /* describes type and geometry */
  215.     struct carditem    *carditem;    /* widget pointers stored here */
  216.     Widget        wform;        /* static part form, or card form */
  217.     static int    did_register;    /* drawing area action registered? */
  218.     static BOOL    have_fonts;
  219.     static XmFontList ftlist[F_NFONTS];
  220.     Arg        args[15];
  221.     int        n, i;
  222.     XmString    label, blank;
  223.     BOOL        editable;
  224.     XtActionsRec    action;
  225.     String        translations =
  226.         "<Btn1Down>:    chart(down)    ManagerGadgetArm()    \n\
  227.          <Btn1Up>:    chart(up)    ManagerGadgetActivate()    \n\
  228.          <Btn1Motion>:    chart(motion)    ManagerGadgetButtonMotion()";
  229.  
  230.     item = *card->form->items[nitem];
  231.     if (item.y < card->form->ydiv) {        /* static or card? */
  232.         wform  = card->wstat;
  233.     } else {
  234.         wform  = card->wcard;
  235.         item.y -= card->form->ydiv;
  236.     }
  237.     item.x  *= pref.scale;
  238.     item.y  *= pref.scale;
  239.     item.xs *= pref.scale;
  240.     item.ys *= pref.scale;
  241.     item.xm *= pref.scale;
  242.     item.ym *= pref.scale;
  243.  
  244.     if (!wform)
  245.         return;
  246.  
  247.     carditem = &card->items[nitem];
  248.     carditem->w0 = carditem->w1 = 0;
  249.     if (evalbool(card, item.invisible_if))
  250.         return;
  251.     label = item.label ? XmStringCreateSimple(item.label) : 0;
  252.     blank = XmStringCreateSimple(" ");
  253.     editable = item.type != IT_PRINT
  254.             && (!card->dbase || !card->dbase->rdonly)
  255.             && !card->form->rdonly
  256.             && !item.rdonly
  257.             && !evalbool(card, item.freeze_if);
  258.  
  259.     if (!have_fonts++)
  260.         for (n=0; n < F_NFONTS; n++) {
  261.             switch(n) {
  262.               case F_HELV:       i = FONT_HELV;    break;
  263.               case F_HELV_O:   i = FONT_HELV_O;    break;
  264.               case F_HELV_S:   i = FONT_HELV_S;    break;
  265.               case F_HELV_L:   i = FONT_HELV_L;    break;
  266.               case F_COURIER:  i = FONT_COURIER;    break;
  267.             }
  268.             ftlist[n] = XmFontListCreate(font[i], "cset");
  269.         }
  270.     switch(item.type) {
  271.       case IT_LABEL:            /* a text without function */
  272.         n = 0;
  273.         XtSetArg(args[n], XmNx,         item.x);           n++;
  274.         XtSetArg(args[n], XmNy,         item.y);           n++;
  275.         XtSetArg(args[n], XmNwidth,     item.xs);           n++;
  276.         XtSetArg(args[n], XmNheight,     item.ys);           n++;
  277.         XtSetArg(args[n], XmNalignment,     JUST(item.labeljust));    n++;
  278.         XtSetArg(args[n], XmNlabelString,label);           n++;
  279.         XtSetArg(args[n], XmNfontList,     ftlist[item.labelfont]);  n++;
  280.         XtSetArg(args[n], XmNhighlightThickness, 0);           n++;
  281.         carditem->w0 = XtCreateManagedWidget("label",
  282.                     xmLabelWidgetClass, wform, args, n);
  283.         break;
  284.  
  285.       case IT_INPUT:            /* arbitrary line of text */
  286.       case IT_PRINT:            /* non-editable text */
  287.       case IT_TIME:                /* date and/or time */
  288.         if (item.xm > 6) {
  289.           n = 0;
  290.           XtSetArg(args[n], XmNx,      item.x);           n++;
  291.           XtSetArg(args[n], XmNy,      item.y);           n++;
  292.           XtSetArg(args[n], XmNwidth,      item.xm - 6);           n++;
  293.           XtSetArg(args[n], XmNheight,      item.ys);           n++;
  294.           XtSetArg(args[n], XmNalignment, JUST(item.labeljust));   n++;
  295.           XtSetArg(args[n], XmNlabelString,label);           n++;
  296.           XtSetArg(args[n], XmNfontList,  ftlist[item.labelfont]); n++;
  297.           XtSetArg(args[n], XmNhighlightThickness, 0);           n++;
  298.           carditem->w1 = XtCreateManagedWidget("label",
  299.                 xmLabelWidgetClass, wform, args, n);
  300.         }
  301.         n = 0;
  302.         XtSetArg(args[n], XmNx,         item.x  + item.xm);       n++;
  303.         XtSetArg(args[n], XmNy,         item.y);           n++;
  304.         XtSetArg(args[n], XmNwidth,     item.xs - item.xm);       n++;
  305.         XtSetArg(args[n], XmNheight,     item.ys);           n++;
  306.         XtSetArg(args[n], XmNalignment,     JUST(item.inputjust));    n++;
  307.         XtSetArg(args[n], XmNlabelString,blank);            n++;
  308.         XtSetArg(args[n], XmNfontList,     ftlist[item.inputfont]); n++;
  309.         XtSetArg(args[n], XmNmaxLength,     item.maxlen?item.maxlen:10);
  310.                                        n++;
  311.         XtSetArg(args[n], XmNmarginHeight, 2);               n++;
  312.         XtSetArg(args[n], XmNeditable,   editable);           n++;
  313.         XtSetArg(args[n], XmNpendingDelete, True);           n++;
  314.         XtSetArg(args[n], XmNbackground, color[editable ?
  315.                          COL_TEXTBACK:COL_BACK]);  n++;
  316.         carditem->w0 = XtCreateManagedWidget("input",
  317.                     xmTextWidgetClass, wform, args, n);
  318.         if (editable)
  319.             XtAddCallback(carditem->w0, XmNactivateCallback,
  320.                 (XtCallbackProc)card_callback,(XtPointer)card);
  321.         break;
  322.  
  323.       case IT_NOTE:                /* multi-line text */
  324.         n = 0;
  325.         XtSetArg(args[n], XmNx,         item.x);           n++;
  326.         XtSetArg(args[n], XmNy,         item.y);           n++;
  327.         XtSetArg(args[n], XmNwidth,     item.xs);           n++;
  328.         XtSetArg(args[n], XmNheight,     item.ym);           n++;
  329.         XtSetArg(args[n], XmNalignment,     JUST(item.labeljust));    n++;
  330.         XtSetArg(args[n], XmNlabelString,label);           n++;
  331.         XtSetArg(args[n], XmNfontList,     ftlist[item.labelfont]);  n++;
  332.         XtSetArg(args[n], XmNhighlightThickness, 0);           n++;
  333.         carditem->w1 = XtCreateManagedWidget("label",
  334.                     xmLabelWidgetClass, wform, args, n);
  335.         n = 0;
  336.         XtSetArg(args[n], XmNx,         item.x);           n++;
  337.         XtSetArg(args[n], XmNy,         item.y + item.ym);       n++;
  338.         XtSetArg(args[n], XmNwidth,     item.xs);           n++;
  339.         XtSetArg(args[n], XmNheight,     item.ys - item.ym);       n++;
  340.         XtSetArg(args[n], XmNhighlightThickness, 1);           n++;
  341.         XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC);       n++;
  342.         carditem->w0 = XtCreateManagedWidget("noteSW",
  343.                     xmScrolledWindowWidgetClass, wform,
  344.                     args, n);
  345.         n = 0;
  346.         XtSetArg(args[n], XmNfontList,     ftlist[item.inputfont]);  n++;
  347.         XtSetArg(args[n], XmNeditMode,     XmMULTI_LINE_EDIT);       n++;
  348.         XtSetArg(args[n], XmNmaxLength,     item.maxlen);           n++;
  349.         XtSetArg(args[n], XmNalignment,     JUST(item.inputjust));    n++;
  350.         XtSetArg(args[n], XmNhighlightThickness, 0);           n++;
  351.         XtSetArg(args[n], XmNshadowThickness, 0);           n++;
  352.         carditem->w0 = XtCreateWidget("note",
  353.                 xmTextWidgetClass, carditem->w0, args, n);
  354.         if (editable)
  355.             XtAddCallback(carditem->w0, XmNactivateCallback,
  356.                 (XtCallbackProc)card_callback,(XtPointer)card);
  357.         break;
  358.  
  359.       case IT_CHOICE:            /* diamond on/off switch */
  360.       case IT_FLAG:                /* square on/off switch */
  361.         n = 0;
  362.         XtSetArg(args[n], XmNx,         item.x);           n++;
  363.         XtSetArg(args[n], XmNy,         item.y);           n++;
  364.         XtSetArg(args[n], XmNwidth,     item.xs);           n++;
  365.         XtSetArg(args[n], XmNheight,     item.ys);           n++;
  366.         XtSetArg(args[n], XmNalignment,     JUST(item.labeljust));    n++;
  367.         XtSetArg(args[n], XmNselectColor,color[COL_TOGGLE]);       n++;
  368.         XtSetArg(args[n], XmNlabelString,label);           n++;
  369.         XtSetArg(args[n], XmNfontList,     ftlist[item.labelfont]);  n++;
  370.         XtSetArg(args[n], XmNhighlightThickness, 1);           n++;
  371.         XtSetArg(args[n], XmNindicatorType, item.type == IT_CHOICE ?
  372.                     XmONE_OF_MANY : XmN_OF_MANY);       n++;
  373.         carditem->w0 = XtCreateManagedWidget("label",
  374.                 xmToggleButtonWidgetClass, wform,
  375.                 args, n);
  376.         if (card->dbase && !card->dbase->rdonly
  377.                 && !card->form->rdonly
  378.                 && !item.rdonly)
  379.             XtAddCallback(carditem->w0, XmNvalueChangedCallback,
  380.                 (XtCallbackProc)card_callback,(XtPointer)card);
  381.         break;
  382.  
  383.       case IT_BUTTON:            /* pressable button */
  384.         n = 0;
  385.         XtSetArg(args[n], XmNx,         item.x);           n++;
  386.         XtSetArg(args[n], XmNy,         item.y);           n++;
  387.         XtSetArg(args[n], XmNwidth,     item.xs);           n++;
  388.         XtSetArg(args[n], XmNheight,     item.ys);           n++;
  389.         XtSetArg(args[n], XmNfontList,     ftlist[item.labelfont]);  n++;
  390.         XtSetArg(args[n], XmNhighlightThickness, 1);           n++;
  391.         XtSetArg(args[n], XmNlabelString,label);           n++;
  392.         carditem->w0 = XtCreateManagedWidget("button",
  393.                 xmPushButtonWidgetClass, wform, args, n);
  394.         XtAddCallback(carditem->w0, XmNactivateCallback,
  395.                 (XtCallbackProc)card_callback,(XtPointer)card);
  396.         break;
  397.  
  398.       case IT_CHART:            /* chart display */
  399.         if (!did_register++) {
  400.             action.string = "chart";
  401.             action.proc   = (XtActionProc)chart_action_callback;
  402.             XtAppAddActions(app, &action, 1);
  403.         }
  404.         n = 0;
  405.         XtSetArg(args[n], XmNx,         item.x);           n++;
  406.         XtSetArg(args[n], XmNy,         item.y);           n++;
  407.         XtSetArg(args[n], XmNwidth,     item.xs);           n++;
  408.         XtSetArg(args[n], XmNheight,     item.ys);           n++;
  409.         XtSetArg(args[n], XmNhighlightThickness, 1);           n++;
  410.         XtSetArg(args[n], XmNlabelString,label);           n++;
  411.         XtSetArg(args[n], XmNtranslations,
  412.                 XtParseTranslationTable(translations));       n++;
  413.         carditem->w0 = XtCreateManagedWidget("chart",
  414.                 xmDrawingAreaWidgetClass, wform, args,n);
  415.         XtAddCallback(carditem->w0, XmNinputCallback,
  416.                 (XtCallbackProc)card_callback,(XtPointer)card);
  417.         XtAddCallback(carditem->w0, XmNexposeCallback,
  418.                 (XtCallbackProc)chart_expose_callback,
  419.                             (XtPointer)card);
  420.         break;
  421.  
  422.       case IT_VIEW:                /* database summary & card */
  423.         break;
  424.     }
  425.     if (label)
  426.         XmStringFree(label);
  427.     XmStringFree(blank);
  428. }
  429.  
  430.  
  431. /*-------------------------------------------------- callbacks --------------*/
  432. /*
  433.  * All of these routines are direct X callbacks.
  434.  */
  435.  
  436. /*ARGSUSED*/
  437. static void mwm_quit_callback(
  438.     Widget                widget,
  439.     XtPointer            card,
  440.     XmToggleButtonCallbackStruct    *data)
  441. {
  442.     XtPopdown(widget);
  443.     XtDestroyWidget(widget);
  444.     free((void *)card);
  445. }
  446.  
  447.  
  448. /*
  449.  * a widget with a chart is exposed or otherwise redrawn. Motif can't do
  450.  * this automatically like with all other types of widgets because charts
  451.  * are drawn with raw Xlib. Do it here.
  452.  */
  453.  
  454. /*ARGSUSED*/
  455. static void chart_expose_callback(
  456.     Widget                widget,
  457.     XtPointer            icard,
  458.     XmDrawingAreaCallbackStruct    *data)
  459. {
  460.     XEvent        dummy;
  461.     CARD        *card = (CARD *)icard;
  462.     int        nitem;
  463.  
  464.     while (XCheckWindowEvent(display, data->window, ExposureMask, &dummy));
  465.     for (nitem=0; nitem < card->nitems; nitem++)
  466.         if (widget == card->items[nitem].w0 ||
  467.             widget == card->items[nitem].w1)
  468.             break;
  469.     if (nitem >= card->nitems ||            /* illegal */
  470.         card->dbase == 0      ||            /* preview dummy card*/
  471.         card->row < 0)                /* card still empty */
  472.         return;
  473.  
  474.     draw_chart(card, nitem);
  475. }
  476.  
  477.  
  478. /*
  479.  * the user pressed the mouse or the return key on an item in the card.
  480.  * If the card references a row in a database, use store() to change the
  481.  * column of that row that is referenced by the item. Redraw the entire
  482.  * card (because a Choice item turns off other Choice items). This is
  483.  * used for all item types except charts, which are more complicated
  484.  * because of drawing and get their own callback, chart_action_callback.
  485.  */
  486.  
  487. /*ARGSUSED*/
  488. static void card_callback(
  489.     Widget                widget,
  490.     XtPointer            icard,
  491.     XmToggleButtonCallbackStruct    *data)
  492. {
  493.     CARD        *card = (CARD *)icard;
  494.     ITEM        *item;
  495.     int        nitem, i, r;
  496.     char        *n, *o;
  497.  
  498.     for (nitem=0; nitem < card->nitems; nitem++)
  499.         if (widget == card->items[nitem].w0 ||
  500.             widget == card->items[nitem].w1)
  501.             break;
  502.     if (nitem >= card->nitems ||            /* illegal */
  503.         card->dbase == 0      ||            /* preview dummy card*/
  504.         card->row < 0)                /* card still empty */
  505.         return;
  506.  
  507.     item = card->form->items[nitem];
  508.     switch(item->type) {
  509.       case IT_INPUT:                /* arbitrary input */
  510.       case IT_TIME:                    /* date and/or time */
  511.       case IT_NOTE:                    /* multi-line text */
  512.         i = (nitem+1) % card->form->nitems;
  513.         for (; i != nitem; i=(i+1)%card->form->nitems) {
  514.             int t = card->form->items[i]->type;
  515.             if ((t == IT_INPUT || t == IT_TIME || t == IT_NOTE) &&
  516.                 !evalbool(card, card->form->items[i]->skip_if))
  517.                 break;
  518.         }
  519.         XmProcessTraversal(card->items[i].w0, XmTRAVERSE_CURRENT);
  520.         card_readback_texts(card, nitem);
  521.         break;
  522.  
  523.       case IT_CHOICE:                /* diamond on/off */
  524.         if (!store(card, nitem, item->flagcode))
  525.             return;
  526.         break;
  527.  
  528.       case IT_FLAG:                    /* square on/off */
  529.         if (!(n = item->flagcode))
  530.             return;
  531.         o = dbase_get(card->dbase, card->row,
  532.                        card->form->items[nitem]->column);
  533.         if (!store(card, nitem, !o || strcmp(n, o) ? n : 0))
  534.             return;
  535.         break;
  536.  
  537.       case IT_BUTTON:                /* pressable button */
  538.         if (item->pressed) {
  539.             if (switch_name) free(switch_name); switch_name = 0;
  540.             if (switch_expr) free(switch_expr); switch_expr = 0;
  541.             n = evaluate(card, item->pressed);
  542.             if (switch_name) {
  543.                 switch_form(switch_name);
  544.                 card = curr_card;
  545.             }
  546.             if (switch_expr)
  547.                 search_cards(card, switch_expr);
  548.             if (n && *n)
  549.                 system(n);
  550.             if (switch_name) free(switch_name); switch_name = 0;
  551.             if (switch_expr) free(switch_expr); switch_expr = 0;
  552.         }
  553.         break;
  554.  
  555.       case IT_VIEW:                    /* database summary */
  556.         break;
  557.     }
  558.     fillout_card(card, TRUE);
  559. }
  560.  
  561.  
  562. /*
  563.  * read back all text fields. This is necessary whenever a card is removed
  564.  * or redrawn because we might not have received a callback for a changed
  565.  * text input field. We get callbacks only if the user presses Return, and
  566.  * not even that on multi-line IT_NOTE fields.
  567.  * The <which> parameter, if >= 0, narrows the readback to a particular item.
  568.  */
  569.  
  570. void card_readback_texts(
  571.     CARD        *card,        /* card that is displayed in window */
  572.     int        which)        /* all -f < 0, one item only if >= 0 */
  573. {
  574.     int        nitem;        /* counter for searching text items */
  575.     int        start, end;    /* first and last item to read back */
  576.     char        *data;        /* data string to store */
  577.     time_t        time;        /* parsed time */
  578.     char        buf[40];    /* if numeric time, temp string */
  579.  
  580.     if (!card || !card->form || !card->form->items || !card->dbase
  581.           ||  card->form->rdonly
  582.           ||  card->dbase->rdonly
  583.           ||  card->row >= card->dbase->nrows)
  584.         return;
  585.     start = which >= 0 ? which : 0;
  586.     end   = which >= 0 ? which : card->nitems-1;
  587.     for (nitem=start; nitem <= end; nitem++) {
  588.         if (!card->items[nitem].w0        ||
  589.             card->form->items[nitem]->rdonly)
  590.             continue;
  591.         switch(card->form->items[nitem]->type) {
  592.           case IT_INPUT:
  593.           case IT_NOTE:
  594.             data = read_text_button_noskipblank(
  595.                         card->items[nitem].w0, 0);
  596.             (void)store(card, nitem, data);
  597.             break;
  598.  
  599.           case IT_TIME:
  600.             data = read_text_button(card->items[nitem].w0, 0);
  601.             switch(card->form->items[nitem]->timefmt) {
  602.               case T_DATE:
  603.                 time = parse_datestring(data);
  604.                 break;
  605.               case T_TIME:
  606.                 time = parse_timestring(data, FALSE);
  607.                 break;
  608.               case T_DURATION:
  609.                 time = parse_timestring(data, TRUE);
  610.                 break;
  611.               case T_DATETIME:
  612.                 time = parse_datetimestring(data);
  613.             }
  614.             sprintf(buf, "%d", time);
  615.             (void)store(card, nitem, buf);
  616.             if (which >= 0)
  617.                 fillout_item(card, nitem, FALSE);
  618.         }
  619.     }
  620.     replace_summary_line(card, card->row);
  621. }
  622.  
  623.  
  624. /*
  625.  * store a data item in the database. The database is just a big array of
  626.  * rows and columns of char strings indexed by the card's row and the item
  627.  * in the card to be set. Items reference a column. Some items, like labels,
  628.  * do not reference any column at all, do not call store() with one of these.
  629.  */
  630.  
  631. static BOOL store(
  632.     register CARD    *card,        /* card the item is added to */
  633.     int        nitem,        /* number of item being added */
  634.     char        *string)    /* string to store in dbase */
  635. {
  636.     if (nitem >= card->nitems        ||
  637.         card->dbase == 0            ||
  638.         card->dbase->rdonly            ||
  639.         card->form->items[nitem]->rdonly || card->form->rdonly)
  640.         return(FALSE);
  641.  
  642.     dbase_put(card->dbase, card->row, card->form->items[nitem]->column,
  643.                                 string);
  644.     print_info_line();
  645.     return(TRUE);
  646. }
  647.  
  648.  
  649. /*-------------------------------------------------- drawing ----------------*/
  650. /*
  651.  * return the text representation of the data string of an IT_TIME database
  652.  * item. This is used by fillout_item and make_summary_line.
  653.  */
  654.  
  655. char *format_time_data(
  656.     char        *data,        /* string from database */
  657.     TIMEFMT        timefmt)    /* new format, one of T_* */
  658. {
  659.     static char    buf[40];    /* for date/time conversion */
  660.     int        value = data ? atoi(data) : 0;
  661.  
  662.     if (!data)
  663.         return("");
  664.     value = atoi(data);
  665.     switch(timefmt) {
  666.       case T_DATE:
  667.         data = mkdatestring(value);
  668.         break;
  669.       case T_TIME:
  670.         data = mktimestring(value, FALSE);
  671.         break;
  672.       case T_DURATION:
  673.         data = mktimestring(value, TRUE);
  674.         break;
  675.       case T_DATETIME:
  676.         sprintf(buf, "%s  %s", mkdatestring(value),
  677.                        mktimestring(value, FALSE));
  678.         data = buf;
  679.     }
  680.     return(data);
  681. }
  682.  
  683.  
  684. /*
  685.  * fill out a card, using the data from the row in the database referenced
  686.  * in the card. If there is no database, print empty strings. If the deps
  687.  * argument is true, a field has changed (and got reprinted separately), so
  688.  * only PRINT and CHART items that may need updating are reprinted. This is
  689.  * done to speed things up. It is called by routines that call store().
  690.  */
  691.  
  692. void fillout_card(
  693.     CARD        *card,        /* card to draw into menu */
  694.     BOOL        deps)        /* if TRUE, dependencies only */
  695. {
  696.     int        i;        /* item counter */
  697.  
  698.     if (card)
  699.         for (i=0; i < card->nitems; i++)
  700.             fillout_item(card, i, deps);
  701.     remake_section_popup(FALSE);
  702. }
  703.  
  704.  
  705. void fillout_item(
  706.     CARD        *card,        /* card to draw into menu */
  707.     int        i,        /* item index */
  708.     BOOL        deps)        /* if TRUE, dependencies only */
  709. {
  710.     BOOL        sens;        /* (de-)sensitize item */
  711.     register ITEM    *item;        /* describes type and geometry */
  712.     Widget        w0, w1;        /* input widget(s) in card */
  713.     char        *data;        /* value string in database */
  714.     char        *eval;        /* evaluated expression, 0=error */
  715.     Arg        arg;        /* for (de-) sensitizing */
  716.  
  717.     w0   = card->items[i].w0;
  718.     w1   = card->items[i].w1;
  719.     item = card->form->items[i];
  720.     sens = item->type == IT_BUTTON && !item->gray_if ||
  721.            item->y < card->form->ydiv ||
  722.            card->dbase && card->row < card->dbase->nrows
  723.                && !evalbool(card, item->gray_if);
  724.     data = !sens || item->type == IT_BUTTON ? 0 :
  725.            dbase_get(card->dbase, card->row, card->form->items[i]->column);
  726.  
  727.     XtSetArg(arg, XmNsensitive, sens);
  728.     if (w0) XtSetValues(w0, &arg, 1);
  729.     if (w1) XtSetValues(w1, &arg, 1);
  730.  
  731.     switch(item->type) {
  732.       case IT_TIME:
  733.         if (sens)
  734.             data = format_time_data(data, item->timefmt);
  735.  
  736.       case IT_INPUT:
  737.         if (!deps) {
  738.             print_text_button_s(w0, data ? data :
  739.                     item->idefault &&
  740.                     (eval = evaluate(card, item->idefault))
  741.                             ? eval : "");
  742.             if (w0) XmTextSetInsertionPosition(w0, 0);
  743.         }
  744.         break;
  745.  
  746.       case IT_NOTE:
  747.         if (!deps && w0) {
  748.             XtUnmanageChild(w0);
  749.             print_text_button_s(w0, data ? data :
  750.                     item->idefault &&
  751.                     (eval = evaluate(card, item->idefault))
  752.                             ? eval : "");
  753.             XmTextSetInsertionPosition(w0, 0);
  754.             XtManageChild(w0);
  755.         }
  756.         break;
  757.  
  758.       case IT_PRINT:
  759.         print_text_button_s(w0, evaluate(card, item->idefault));
  760.         break;
  761.  
  762.       case IT_CHOICE:
  763.       case IT_FLAG:
  764.         set_toggle(w0, data && item->flagcode
  765.                     && !strcmp(data, item->flagcode));
  766.         break;
  767.  
  768.       case IT_CHART:
  769.         draw_chart(card, i);
  770.         break;
  771.  
  772.       case IT_VIEW:
  773.         break;
  774.     }
  775. }
  776.